home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UCRASM25.ARJ / MEMORY.ASM < prev    next >
Assembly Source File  |  1991-10-12  |  24KB  |  852 lines

  1.         extrn    PSP:word
  2. ;
  3. StdGrp        group    StdData, StdLib
  4. ;
  5. StdData        segment    para public 'sldata'
  6. ;
  7. ; Memory allocation routines: MemInit, malloc, and free.
  8. ;
  9. ;
  10. ; Local variables:
  11. ;
  12. StartOfHeap    dw    ?
  13. SizeOfHeap    dw    ?
  14. FreeSpace    dw    ?
  15. ;
  16. ; Memory manager data structure:
  17. ;
  18. ;        option    oldstructs
  19. mmstruct    struc
  20. blksize        dw    ?
  21. bwdptr        dw    ?
  22. fwdptr        dw    ?
  23. refcnt        dw    ?
  24. freebwdptr    dw    ?        ;Only if in the free list.
  25. freefwdptr    dw    ?        ;Only if in the free list.
  26. mmstruct    ends
  27. ;
  28. ; When using es and ds as pointers into the heap, the following equates
  29. ; come in handy.
  30. ;
  31. esptr        equ    word ptr es:[0]
  32. dsptr        equ    word ptr ds:[0]
  33. ;
  34. NIL        equ    0
  35. StdData        ends
  36. ;
  37. ;
  38. ;
  39. ;
  40. ;
  41. stdlib        segment    para public 'slcode'
  42.         assume    cs:StdGrp, ds:nothing
  43. ;
  44. ;
  45. ; MemInit- Initializes the memory manager.
  46. ;
  47. ;    On entry- DX contains the number of paragraphs of memory to reserve
  48. ;          for other programs.  The default (in shell.asm) is 0.  If
  49. ;          you intend to execute other programs from the program you're
  50. ;          writing, you will have to reserve an appropriate amount of
  51. ;          space for that program.  If you attempt to reserve too
  52. ;          much space, then this code splits the available free memory
  53. ;          in half and gives half to the heap and reserves half for
  54. ;          other programs.  If this is desirable, simply set DX to
  55. ;          0ffffh before calling MemInit.
  56. ;
  57. ;    On Exit-  No error if carry is clear.  In such a case, CX contains
  58. ;          the number of paragraphs of memory actually allocated.
  59. ;          AX contains the starting segment address of the free
  60. ;          memory block.
  61. ;
  62. ;          If carry is set, then an error occurred, AX contains the
  63. ;          error code (DOS).
  64. ;
  65. ; WARNING: for this routine to work properly, the calling program has to
  66. ; declare (and initialize) a word variable by the name PSP which contains
  67. ; the program's program segment prefix value.  Furthermore, the last segment
  68. ; in the program must be "zzzzzzseg" and this guy should NOT contain any
  69. ; valid data.
  70. ;
  71.         public    sl_MemInit
  72. sl_MemInit    proc    far
  73.         push    bx
  74.         push    dx
  75.         push    es
  76. ;
  77. ; Compute program size, in paragraphs:
  78. ;
  79.         mov    ax, seg PSP
  80.         mov    es, ax
  81.         mov    bx, es:PSP
  82.         mov    es, bx
  83.         mov    ax, seg zzzzzzseg
  84.         sub    ax, bx
  85.         inc    bx            ;Safety margin
  86.         inc    bx
  87.         mov    ah, 4ah            ;Memory block resize opcode
  88.         int    21h
  89. ;
  90. ; Now ask for a ridiculous amount of memory so we can find out how much is
  91. ; available.
  92. ;
  93.         mov    bx, 0ffffh
  94.         mov    ah, 48h            ;Alloc block opcode
  95.         int    21h
  96. ;
  97. ;
  98. ; Allocate storage for the heap.
  99. ;
  100.         cmp    bx, dx            ;See if DX is too large.
  101.         ja    GoodHeap
  102.         shr    bx, 1            ;Use half remaining space.
  103.         jmp    short SetNewAlloc
  104. ;
  105. GoodHeap:    sub    bx, dx            ;Make room for other apps.
  106. SetNewAlloc:    cmp    bx, 10h            ;Make sure there is some room.
  107.         jbe    ErrorAlloc2
  108.         mov    ah, 48h            ;Alloc block opcode
  109.         int    21h
  110.         jc    ErrorAlloc        ;Shouldn't happen, but...
  111. ;
  112. ; Okay, we've just allocated the block, now set up our own local variables
  113. ; so we can keep track of the data.
  114. ;
  115.         mov    StdGrp:StartOfHeap, ax    ;Save pointer to memory.
  116.         mov    StdGrp:FreeSpace, ax    ;Save pointer to 1st free blk.
  117.         mov    StdGrp:SizeOfHeap, bx    ;Size of heap in paragraphs.
  118.         mov    es, ax            ;Init pointer to heap.
  119.                 xor    ax, ax
  120.         mov    esptr.blksize, bx    ;Size of this block (paras).
  121.         mov    esptr.bwdptr, ax      ;Back pointer is NIL.
  122.         mov    esptr.fwdptr, ax      ;Fwd pointer is NIL.
  123.         mov    esptr.refcnt, ax      ;Reference Count is zero.
  124.         mov    esptr.freebwdptr, ax     ;Free list bwd ptr is NIL.
  125.         mov    esptr.freefwdptr, ax     ;Free list fwd ptr is NIL.
  126.         mov    cx, bx            ;Return size in CX
  127.         mov    ax, StdGrp:StartOfHeap
  128.         clc
  129.         jmp    MemInitDone
  130. ;
  131. ErrorAlloc2:    mov    ax, 8            ;Insufficient memory error.
  132. ErrorAlloc:    stc
  133. MemInitDone:    pop     es
  134.         pop    dx
  135.         pop    bx
  136.         ret
  137. sl_MemInit    endp
  138. ;
  139. ;
  140. ;
  141. ;
  142. ;============================================================================
  143. ;
  144. ;    *     *      *      *        *         *****       *****
  145. ;    **   **     * *     *        *        *     *     *     *
  146. ;    * * * *    *   *    *        *        *     *     *
  147. ;    *  *  *    *****    *        *        *     *     *
  148. ;    *     *    *   *    *      *        *     *     *
  149. ;    *     *    *   *    *        *        *     *     *     *
  150. ;    *     *    *   *    *****    *****     *****       *****
  151. ;
  152. ;============================================================================
  153. ;
  154. ;
  155. ; malloc-  On entry, CX contains a byte count.  Malloc allocates a block
  156. ;       of storage of the given size and returns a pointer to this block
  157. ;       in ES:DI.  The value in ES:DI is always normalized, so you can
  158. ;       compare pointers allocated via malloc as 32-bit values.  Note
  159. ;       that malloc always allocates memory in paragraph chunks.
  160. ;       Therefore, this routine returns the actual number of bytes of
  161. ;       memory allocated in the CX register (this may be as much as 15
  162. ;       greater than the actual number asked for).
  163. ;
  164. ;       Malloc returns carry clear if it allocated the storage without
  165. ;       error.  It returns carry set if it could not find a block large
  166. ;       enough to satisfy the request.
  167. ;
  168. ;
  169. ; Data structure for memory allocation blocks:
  170. ;
  171. ; offset:
  172. ;
  173. ;   0    Size of Blk
  174. ;   2   Back link
  175. ;   4   Fwd Link
  176. ;   6   Reference Count
  177. ;   8   Data, if this block is allocated, prev link if on free list.
  178. ;  10    Data, if this block is allocated, next link if on free list.
  179. ;
  180. ;
  181. ;
  182.         public    sl_malloc
  183. sl_malloc    proc    far
  184.         push    ax
  185.         push    si
  186.         push    ds
  187. ;
  188. ; Convert byte count to paragraph count, since we always allocate whole
  189. ; paragraphs.
  190. ;
  191.         add    cx, 8            ;We have six bytes of overhead!
  192.         rcr    cx, 1            ;Use rcr because of add above.
  193.         adc    cx, 0
  194.         shr    cx, 1
  195.         adc    cx, 0
  196.         shr    cx, 1
  197.         adc    cx, 0
  198.         shr    cx, 1
  199.         adc    cx, 0
  200. ;
  201. ; Go find a block in the free list which is large enough.
  202. ;
  203. ; Uses the following algorithm:
  204. ;
  205. ;
  206.         cmp    StdGrp:FreeSpace, 0        ;See if no free space.
  207.         jz    MemoryFull
  208.         mov    ds, StdGrp:FreeSpace
  209.         mov    ax, ds            ;In case first block is it.
  210. FindBlk:    cmp    cx, dsptr.blksize    ;See if blk is large enuf.
  211.         jbe    FoundBlk        ;Go for it!
  212.         mov     ax, dsptr.freefwdptr    ;Get ptr to next free block.
  213.         mov    ds, ax            ;Set up pointer.
  214.         or    ax, ax            ;See if NIL
  215.                 jnz    FindBlk            ;Repeat until NIL.
  216. ;
  217. ; If we drop down here, we've got some big problems.
  218. ;
  219. MemoryFull:    stc
  220.         pop    ds
  221.         pop    si
  222.         pop    ax
  223.         mov    es, StdGrp:StartOfHeap    ;In case they use this ptr
  224.         mov    di, 8            ; anyway.
  225.         ret
  226. ;
  227. ; When we come down here, we've found a block large enough to satisfy the
  228. ; current memory request.  If necessary, split the block up into two
  229. ; pieces and return the unused half back to the free pool.
  230. ;
  231. FoundBlk:       jne    SplitBlock
  232. ;
  233. ;
  234. ;
  235. ;***************************************************************************
  236. ; Exact fit, remove this guy from the free list and go for it!
  237. ;***************************************************************************
  238. ;
  239. ; There are four cases to deal with if this is an exact fit:
  240. ;
  241. ;    1) The block we're allocating is the first block in the free list.
  242. ;       In this case, FreeSpace points at this block and the freebwdptr
  243. ;       entry is NIL.
  244. ;
  245. ;    2) The block we're allocating is neither the first or last in the
  246. ;       free list.
  247. ;
  248. ;    3) The block we're allocating is the last block in the free list.
  249. ;       In this case, the freefwdptr will be NIL.
  250. ;
  251. ;    4) The block is both the first and last (i.e., only) block in the
  252. ;       the free list.
  253. ;
  254. ; At this point, DS points at the block we're going to allocate.
  255. ;
  256.         mov    ax, dsptr.freefwdptr    ;Pointer to next free block.
  257.         cmp    dsptr.freebwdptr, NIL    ;First item in list?
  258.         jnz    NotFirst
  259. ;
  260. ; Case (1) and (4) drop down here.
  261. ;
  262. ; If this is the first free block in the free link list, point FreeSpace
  263. ; beyond this guy rather than going through the usual linked list stuff.
  264. ;
  265. ; AX contains a pointer to the next free block (after this one) if it exists.
  266. ; DS points at the current free block.
  267. ;
  268. ; Since we are removing the first free block, we need to update the FreeSpace
  269. ; pointer so that it points at the next free block in the free block list.
  270. ;
  271.         mov    StdGrp:FreeSpace, ax    ;Note: AX may be NIL if case (4).
  272. ;
  273. ; See if there is another block after this one.  If not (case 4) then jump
  274. ; off to FixThisBlk.
  275. ;
  276.         or    ax, ax            ;Is there another free blk?
  277.         jz    FixThisBlk        ;If not, don't patch next adrs.
  278. ;
  279. ; Case (1), only, down here.  The current block is the one we want and
  280. ; there is another free block after this one.  AX Points at the next free
  281. ; block.  DS points at the current block.
  282. ;
  283.         mov    es, ax               ;Point ES at next free block.
  284.         mov    esptr.freebwdptr, NIL    ;Set next guy's back link to NIL.
  285.         jmp    short FixThisBlk
  286. ;
  287. ; If the current block is not the first free block in the free block list
  288. ; handle it down here. This corresponds to cases 2 or 3.  On entry, DS
  289. ; points at the current block, AX points at the next free block (if present).
  290. ;
  291. NotFirst:    mov    es, dsptr.freebwdptr    ;Get ptr to prev blk.
  292.         mov    esptr.freefwdptr, ax    ;Skip over current blk.
  293.         mov    ax, es            ;Load AX with prev blk adrs.
  294. ;
  295. ; Now we need to figure out if there is a next free block (is this case 2?).
  296. ;
  297.         cmp    dsptr.freefwdptr, NIL
  298.         jz    FixThisBlk
  299. ;
  300. ; Definitely Case (2) here.  Patch the next free block's prev field with
  301. ; the address of the previous block.
  302. ;
  303.         mov    es, dsptr.freefwdptr    ;Point ES at next block.
  304.         mov    esptr.freebwdptr, ax    ;Save link to prior block.
  305. ;
  306. ; All four cases converge down here to clean up things and store the
  307. ; overhead info for the newly allocated block.
  308. ;
  309. FixThisBlk:    mov    dsptr.blksize, cx    ;Save its size.
  310.         mov    dsptr.refcnt, 1        ;Reference count = 1.
  311.         mov    di, 8            ;Pointer to data area.
  312.         mov    ax, ds
  313.         mov    es, ax
  314.         shl    cx, 1            ;Convert paragraph size to
  315.         shl    cx, 1            ; bytes.
  316.         shl    cx, 1
  317.         shl    cx, 1
  318.         pop    ds
  319.         pop    si
  320.         pop    ax
  321.         clc
  322.         ret
  323. ;
  324. ;****************************************************************************
  325. ; The current free block is bigger than we need, SPLIT it in half down here.
  326. ;****************************************************************************
  327. ;
  328. ;
  329. ; If allocating this block splits a free block in half, we handle that
  330. ; down here.
  331. ;
  332. SplitBlock:     mov    ax, ds            ;Get start of block.
  333.         add    ax, dsptr.blksize    ;Add in size of block.
  334.         sub    ax, cx            ;Subtract part we're keeping.
  335.         mov    es, ax            ;Point at data block.
  336.         mov    esptr.blksize, cx    ;Save size of block
  337.         mov    esptr.bwdptr, ds    ;Save back pointer.
  338.         mov    esptr.refcnt, 1        ;Init reference count.
  339.         mov    ax, dsptr.fwdptr    ;Get prev fwd ptr.
  340.         mov    dsptr.fwdptr, es    ;Save new fwd point in free blk.
  341.         mov    esptr.fwdptr, ax    ;New forward pointer for us.
  342.         mov    si, es            ;Save ptr to this blk.
  343.         mov    es, ax            ;Point es at last blk.
  344.         mov    esptr.bwdptr, si    ;Chain it in properly.
  345.         mov    es, si            ;Restore so we can return it.
  346.         mov    ax, dsptr.blksize    ;Compute new size of free blk.
  347.         sub    ax, cx
  348.         mov    dsptr.blksize, ax
  349.         mov    di, 8            ;Init pointer to data.
  350.         shl    cx, 1            ;Convert paragraph size to
  351.         shl    cx, 1            ; bytes.
  352.         shl    cx, 1
  353.         shl    cx, 1
  354.         pop    ds
  355.         pop    si
  356.         pop    ax
  357.         clc
  358.         ret
  359. ;
  360. sl_malloc    endp
  361. ;
  362. ;
  363. ;
  364. ;===========================================================================
  365. ;
  366. ;  ******     *****       ******     ******
  367. ;  *          *    *      *          *
  368. ;  *          *    *      *          *
  369. ;  ****       * ***       ****       ****
  370. ;  *          *  *        *          *
  371. ;  *          *   *       *          *
  372. ;  *          *    *      ******     ******
  373. ;
  374. ;===========================================================================
  375. ;
  376. ; Free-    Returns a block of storage to the free list.
  377. ;
  378. ; On Entry-    ES:DI points at the block to free.
  379. ; On Exit-    Carry is clear if free was okay, set if invalid pointer.
  380. ;
  381. ;
  382.         public    sl_free
  383. sl_free        proc    far
  384.         push    ax
  385.         push    si
  386.         push    ds
  387.         push    es
  388.         mov    si, di
  389. ;
  390. ; See if this is a valid pointer:
  391. ;
  392.         cmp    si, 8
  393.         jne    BadPointer
  394.         mov    si, es            ;Make seg ptr convenient.
  395.         mov    ds, StdGrp:StartOfHeap
  396.         cmp    si, StdGrp:StartOfHeap    ;Special case if first block.
  397.         jne    Not1stBlock
  398. ;
  399. ; The block the user wants to free up is the very first block.  Handle that
  400. ; right here.
  401. ;
  402.         cmp    dsptr.refcnt, 0
  403.         je    BadPointer
  404.         dec    dsptr.refcnt        ;Decrement reference count.
  405.         jnz    QuitFree        ;Done if other references.
  406. ;
  407. ; Call coalesce to possibly join this block with the next block.  We do not
  408. ; have to check to see if this call joins the current block with the prev
  409. ; block because the current block is the very first block in the memory
  410. ; space.
  411. ;
  412.         call    Coalesce
  413. ;
  414. ; Adjust all the pointers as appropriate:
  415. ;
  416.         mov    dsptr.freebwdptr, NIL
  417.         mov    ax, StdGrp:FreeSpace    ;Get and set up the fwd ptr.
  418.         mov    dsptr.freefwdptr, ax
  419.         mov    es, StdGrp:FreeSpace
  420.         mov    esptr.freebwdptr, ds    ;Set up other back pointer.
  421.         mov    StdGrp:FreeSpace, ds    ;Fix FreeSpace.
  422.         jmp    short QuitFree
  423. ;
  424. ;
  425. BadPointer:    stc
  426.         jmp    short Quit2
  427. ;
  428. QuitFree:    clc
  429. Quit2:        pop    es
  430.         pop    ds
  431.         pop    si
  432.         pop    ax
  433.         ret
  434. ;
  435. ; If this is not the first block in the list, see if we can coalesce any
  436. ; free blocks immediately around this guy.
  437. ;
  438. Not1stBlock:    cmp    esptr.refcnt, 0
  439.         je    BadPointer
  440.         dec    esptr.refcnt        ;Decrement reference count.
  441.         jnz    QuitFree        ;Done if other references.
  442. ;
  443.         call    Coalesce
  444.         jc    QuitFree
  445. ;
  446. ; Okay, let's put this free block back into the free list.
  447. ;
  448.         mov    ax, StdGrp:FreeSpace
  449.         mov    esptr.freefwdptr, ax    ;Set as pointer to next item.
  450.         mov    esptr.freebwdptr, NIL    ;NIL back pointer.
  451.         mov    StdGrp:FreeSpace, es
  452.         jmp    QuitFree
  453. ;
  454. sl_free        endp
  455. ;
  456. ;
  457. ; Coalesce routine: On entry, ES points at the block we're going to free.
  458. ; This routine coalesces the current block with any free blocks immediately
  459. ; around it and then returns ES pointing at the new free block.
  460. ; This routine returns the carry flag set if it was able to coalesce the
  461. ; current free block with a block immediately in front of it.
  462. ; It returns the carry clear if this was not the case.
  463. ;
  464. ;
  465. Coalesce    proc    near
  466.         push    ds
  467.         push    es
  468. ;
  469.         mov    ds, esptr.fwdptr        ;Get next contiguous block.
  470.         cmp    dsptr.refcnt, 0        ;Is that block free?
  471.         jnz    NextBlkNotFree
  472. ;
  473. ; If the next block is free, merge it into the current block here.
  474. ;
  475. ; Memory arrangement is currently something like this:
  476. ;
  477. ;        +------------------------+      +---------+   <-These are dbl links.
  478. ;        |                        |      |         |
  479. ;   |prevfree|     |CurFreeBlk| |FollowingBlk|   |NextFreeBlk|
  480. ;
  481. ; We want to wind up with:
  482. ;
  483. ;
  484. ;        +------------------------------------------+   <-These are dbl links.
  485. ;        |                                          |
  486. ;   |prevfree|     |CurFreeBlk| |FollowingBlk|   |NextFreeBlk|
  487. ;
  488. ;
  489. ; First, merge the current free block and the following block together.
  490. ;
  491.         mov    ax, dsptr.blksize        ;Get size of next block.
  492.         add    esptr.blksize, ax        ; Join the blocks together.
  493.         mov    ax, dsptr.fwdptr
  494.         mov    esptr.fwdptr, ax
  495.         or    ax, ax
  496.         jz    DontSetBwd
  497.         push    ds
  498.         mov    ds, ax
  499.         mov    dsptr.bwdptr, es
  500.         pop    ds
  501. ;
  502. ; Make sure that there is a |prevfree| block.
  503. ;
  504. DontSetBwd:    mov    ax, dsptr.freebwdptr
  505.         or    ax, ax
  506.         jz    SetFreeSpcPtr
  507. ;
  508. ; prevfree.fwd := following.fwd;
  509. ;
  510.         mov    es, dsptr.freebwdptr    ;Point ES at previous guy.
  511.         mov    ax, dsptr.freefwdptr
  512.         mov    esptr.freefwdptr, ax    ;Skip over current guy.
  513. ;
  514. ; If the fwd pointer is NIL, no need to continue.
  515. ;
  516.         or    ax, ax            ;See if end of list.
  517.         jz    NextBlkNotFree
  518. ;
  519. ; nextfree.bwd := following.bwd (prevfree).
  520. ;
  521.         mov    ax, es            ;Save ptr to this guy.
  522.         mov    es, dsptr.freefwdptr
  523.         mov    esptr.freebwdptr, ax
  524.         jmp    short NextBlkNotFree
  525. ;
  526. ; If FollowingBlk is the first free block in the free list, we have to
  527. ; execute the following code.
  528. ;
  529. SetFreeSpcPtr:  mov    es, dsptr.freefwdptr
  530.         mov    esptr.freebwdptr, NIL
  531.         mov    StdGrp:FreeSpace, es
  532. ;
  533. ;
  534. ;
  535. ; After processing the block following this block, or if the next block
  536. ; was not free, come down here and check to see if the previous block
  537. ; was free.
  538. ;
  539. NextBlkNotFree:    pop    es        ;Restore pointer to current block.
  540.         push    es
  541.         mov    ax, esptr.bwdptr
  542.         or    ax, ax        ;Is it a NIL pointer
  543.         jz    NoPrevBlock
  544.         mov    ds, ax
  545.         cmp     dsptr.refcnt, 0    ;Is that block free?
  546.         jnz    NoPrevBlock
  547. ;
  548. ; Okay, the block in front is free.  Merge the current block into that one.
  549. ;
  550.         mov    ax, esptr.blksize
  551.         add    dsptr.blksize, ax
  552.         mov    ax, esptr.fwdptr
  553.         mov    dsptr.fwdptr, ax
  554.         or    ax, ax            ;See if there is a next blk.
  555.         jz    NoNextBlk
  556.         mov    es, ax
  557.         mov    esptr.bwdptr, ds
  558. NoNextBlk:    stc
  559.         pop    es
  560.         pop    ds
  561.         ret
  562. ;
  563. NoPrevBlock:    clc
  564.         pop    es
  565.         pop    ds
  566.         ret
  567. Coalesce    endp
  568. ;
  569. ;
  570. ;============================================================================
  571. ;
  572. ; *****      *******       *      *        *         *****       *****
  573. ; *    *     *            * *     *        *        *     *     *     *
  574. ; *    *     *           *   *    *        *        *     *     *
  575. ; *****      *****       *****    *        *        *     *     *
  576. ; *  *       *           *   *    *       *        *     *     *
  577. ; *   *      *           *   *    *        *        *     *     *     *
  578. ; *    *     *******     *   *    *****    *****     *****       *****
  579. ;
  580. ;============================================================================
  581. ;
  582. ;
  583. ; REALLOC - This routine expects a pointer in ES:DI and a new size in CX.
  584. ;        If the specified block is larger than the value in CX then
  585. ;        realloc shrinks the size of the block and returns the left over
  586. ;        information to the system heap.  If CX is larger than the speci-
  587. ;        fied block then realloc allocates a new block and copies the
  588. ;        data from the old block to the new block and then frees the
  589. ;        old block.  In any case, realloc returns a pointer to the
  590. ;        (possibly new) block in ES:DI.  Carry=0 on return if no error,
  591. ;        carry=1 on return if there wasn't enough room on the heap to
  592. ;        reallocate a larger block.
  593. ;
  594.         public    sl_realloc
  595. sl_realloc    proc    far
  596.         cmp    di, 8            ;Is this a realistic pointer?
  597.         jz    DoREALLOC
  598.         stc                ;Return with error, if not.
  599.         ret
  600. ;
  601. DoREALLOC:    push    ax 
  602.         push    cx
  603.         push    ds
  604.         push    si
  605. ;
  606. ;
  607. ; Convert byte count to paragraph count, since we always allocate whole
  608. ; paragraphs.
  609. ;
  610.         add    cx, 8            ;We have eight bytes of overhead!
  611.         rcr    cx, 1            ;Use rcr because of add above.
  612.         adc    cx, 0
  613.         shr    cx, 1
  614.         adc    cx, 0
  615.         shr    cx, 1
  616.         adc    cx, 0
  617.         shr    cx, 1
  618.         adc    cx, 0
  619. ;
  620. ; See if the new block size is larger or smaller than the old block size.
  621. ;
  622.         cmp    cx, esptr.BlkSize
  623.         ja    MakeBigger
  624. ;
  625. ; New desired size is less than or equal to the current size.  If no more
  626. ; than 32 bytes larger, don't even bother with the operation.
  627. ;
  628.         inc    cx
  629.         inc    cx
  630.         cmp    cx, esptr.BlkSize
  631.         jae    ReallocDone
  632.         dec    cx
  633.         dec    cx
  634. ;
  635. ; Okay, the new block size is seriously smaller here.  Turn the last group
  636. ; of bytes into a free block.
  637. ;
  638.         mov    ax, es            ;Get ptr to block
  639.         add    ax, cx            ;Add in new length
  640.         mov    ds, ax            ;Point at new block.
  641.         mov    ax, esptr.BlkSize    ;Compute the size of the
  642.         sub    ax, cx            ; new block.
  643.         mov    dsptr.BlkSize, ax    ;Save away the link.
  644.         mov    dsptr.bwdptr, es    ;Set up back pointer.
  645.         mov    ax, esptr.fwdptr    ;Copy old fwd ptr to new
  646.         mov    dsptr.fwdptr, ax    ; fwd ptr.
  647.         mov    dsptr.refcnt, 1        ;Init reference count to 1.
  648.         mov    esptr.fwdptr, ds    ;Set up new fwd ptr.
  649.         mov    esptr.BlkSize, cx    ;Set up new length.
  650.         push    es 
  651.         mov    di, 8
  652.         mov    ax, ds
  653.         mov    es, ax
  654.         call    sl_free            ;Free the new block.
  655.         mov    di, 8
  656.         pop    es            ;Get pointer to original blk
  657. ;
  658. ReAllocDone:    pop    si 
  659.         pop    ds 
  660.         pop    cx
  661.         pop    ax
  662.         clc
  663.         ret
  664. ;
  665. ;
  666. ;
  667. ; If they had the nerve to want this block larger, come down here and allocate
  668. ; a new block, copy the old data to the new block, and then free the old block.
  669. ;
  670. ;
  671. MakeBigger:    mov    ax, es            ;Preserve pointer to old blk.
  672.         mov    ds, ax
  673.         mov    si, di            ;Contains "8".
  674.         call    sl_malloc        ;Allocate new block.
  675.         jc    BadRealloc
  676. ;
  677. ; Okay, copy the old block to the new block.  Note that both SI and DI
  678. ; contain 8 at this point.  We can make this assumption here because,
  679. ; after all, this is the memory manager code and it knows the internal
  680. ; representation.
  681. ;
  682.         mov    cx, dsptr.BlkSize    ;Get original block size
  683.         shl    cx, 1            ;Convert from paragraphs
  684.         shl    cx, 1            ; to word count.
  685.         shl    cx, 1
  686.         pushf
  687.         cld
  688.     rep    movsw                ;Note we're moving words!
  689.         popf
  690. ;
  691. ; Okay, free up the old block and we're done.
  692. ;
  693.         mov    di, 8
  694.         push    es               ;Save ptr to new block.
  695.         mov    ax, ds
  696.         mov    es, ax
  697.         call    sl_free
  698.         clc
  699.         mov    di, 8            ;Restore new block ptr.
  700.         pop    es 
  701.         pop    si 
  702.         pop    ds 
  703.         pop    cx 
  704.         pop    ax
  705.         ret
  706. ;
  707. BadRealloc:    stc
  708.         pop    si 
  709.         pop    ds 
  710.         pop    cx 
  711.         pop    ax
  712.         ret
  713. sl_realloc    endp
  714. ;
  715. ;
  716. ;
  717. ;
  718. ;============================================================================
  719. ;
  720. ;   ********      *        *     ********    ********    *******   *******
  721. ;   *       *     *        *     *       *   *       *      *      *      *
  722. ;   *       *     *        *     *       *   *       *      *      *      *
  723. ;   *       *     *        *     ********    ********       *      *******
  724. ;   *       *     *        *     *           *              *      *   *
  725. ;   *       *     *        *     *           *              *      *    *
  726. ;   *       *     *        *     *           *              *      *     *
  727. ;   ********       ********      *           *              *      *      *
  728. ;
  729. ;============================================================================
  730. ;
  731. ;
  732. ; Dupptr - Bumps up the reference count for a particular pointer by one.
  733. ;       Returns carry = 1 if initial pointer is illegal, returns carry=0
  734. ;       if no error.  Returns pointer in ES:DI.  You must pass the pointer
  735. ;       to increment in ES:DI.
  736. ;
  737.         public    sl_DupPtr
  738. sl_DupPtr    proc    far
  739.         cmp    di, 8            ;See if this is a valid ptr.
  740.         je    GoodPtr
  741.         stc
  742.         ret
  743. ;
  744. GoodPtr:    inc    esptr.refcnt        ;Bump up the reference cnt.
  745.         clc
  746.         ret
  747. sl_DupPtr    endp
  748. ;
  749. ;
  750. ;============================================================================
  751. ;
  752. ; *****   *****   *****   *   *   *   *   *****     *     *****
  753. ;   *     *         *     **      *   *   *        * *    *    *
  754. ;   *      ***      *     * * *   *****   ***     *****   *    *
  755. ;   *         *     *     *  **   *   *   *       *   *   *****
  756. ;   *         *     *     *   *   *   *   *       *   *   *
  757. ; *****   *****   *****   *   *   *   *   *****   *   *   *
  758. ;
  759. ;============================================================================
  760. ;
  761. ; IsInHeap-    Returns carry clear if the pointer passed in es:di is within
  762. ;        the heap.  Returns carry set if this pointer is outside the
  763. ;        heap.
  764. ;
  765.         public    sl_IsInHeap
  766. sl_IsInHeap    proc    far
  767.         push    ax
  768.         push    bx
  769.         mov    bx, es
  770.         mov    ax, StdGrp:StartOfHeap
  771.         cmp    bx, ax
  772.         jb    Outside
  773.         add    ax, StdGrp:SizeOfHeap
  774.         mov    bx, es
  775.         cmp    bx, ax
  776.         ja    Outside
  777.         clc
  778.         pop    bx
  779.         pop    ax
  780.         ret
  781. ;
  782. Outside:    stc
  783.         pop    bx
  784.         pop    ax
  785.         ret
  786. sl_IsInHeap    endp
  787. ;
  788. ;
  789. ;
  790. ;
  791. ;============================================================================
  792. ;
  793. ; *****   *****   *****       *****   *****
  794. ;   *     *       *    *     *     *    *
  795. ;   *      ***    *****      *     *****
  796. ;   *         *   *          *     * *
  797. ;   *         *   *          *     *  *
  798. ; *****   *****   *          *     *   *
  799. ;
  800. ;============================================================================
  801. ;
  802. ; IsPtr-    Returns the carry flag clear if es:di points at the beginning
  803. ;        of an allocated block in the heap.  Returns with the carry
  804. ;        flag clear if es:di points at a deallocated block.
  805. ;
  806.         public    sl_IsPtr
  807. sl_IsPtr    proc    far
  808.         cmp    di, 8         ;All of our ptrs have an offset of 8.
  809.         jne    NotPtr2
  810.         push    ax
  811.         push    bx
  812.         push    es
  813.         mov    ax, es
  814. ;
  815.         mov    bx, StdGrp:StartOfHeap
  816. CmpLoop:    cmp    bx, ax
  817.         je    MightBe
  818.         ja    NotPtr
  819.         mov    es, bx
  820.         mov    bx, esptr.fwdptr
  821.         or    bx, bx        ;See if NIL link.
  822.         jnz    CmpLoop
  823. ;
  824. NotPtr:        pop    es
  825.         pop    bx
  826.         pop    ax
  827. NotPtr2:    stc
  828.         ret
  829. ;
  830. ; Might be the pointer, let's see if this guy's allocation count is greater
  831. ; than zero.
  832. ;
  833. MightBe:    mov    es, bx
  834.         cmp    esptr.blksize, 0
  835.         je    NotPtr
  836.         clc
  837.         pop    es
  838.         pop    bx
  839.         pop    ax
  840.         ret
  841. sl_IsPtr    endp
  842. ;
  843. ;
  844. ;
  845. stdlib        ends
  846. ;
  847. ;
  848. zzzzzzseg    segment    para public 'zzzzzz'
  849. LastBytes    db    16 dup (?)
  850. zzzzzzseg    ends
  851.         end
  852.